package org.deng.learn.concurrent.basic;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ Author: DengLibin
 * @ Description: 生产者消费者模式
 * LinkedBlockingQueue是一个线程安全的阻塞队列，它实现了BlockingQueue接口，BlockingQueue接口继承自java.util.Queue接口，
 * 并在这个接口的基础上增加了take和put方法，这两个方法正是队列操作的阻塞版本。

 内部基于ReentrantLock 和 Condition实现

 由于LinkedBlockingQueue实现是线程安全的，实现了先进先出等特性，是作为生产者消费者的首选;LinkedBlockingQueue 可以指定容量，
 ，不指定的话，默认最大是Integer.MAX_VALUE;其中主要用到put和take方法，
 put方法在队列满的时候会阻塞直到有队列成员被消费，take方法在队列空的时候会阻塞，直到有队列成员被放进来。


 添加元素：
 add方法在添加元素的时候，若超出了度列的长度会直接抛出异常
 对于put方法，若向队尾添加元素的时候发现队列已经满了会发生阻塞一直等待空间，以加入元素。
 offer方法在添加元素时，如果发现队列已满无法添加的话，会直接返回false

 取元素：
 remove:若队列为空，抛出NoSuchElementException异常。
 take:若队列为空，发生阻塞，等待有元素
 poll: 若队列为空，返回null。


 * @ DateTime:  23:14 2018/5/7 0007
 */
public class LinkedBlockingQueueDemo {

    static LinkedBlockingDeque<String> queue = new LinkedBlockingDeque<>();
    static  int x = 0;
    static AtomicInteger y = new AtomicInteger(0);
    public static void main(String[] args){

        CountDownLatch countDownLatch = new CountDownLatch(1);
        //1个线程生产
        new Thread(()->{
            for(int i = 0; i < 100; i++){
                try {
                    queue.put(i+"");//放入元素 满了 会阻塞 //
                    x++;
                    TimeUnit.MILLISECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            countDownLatch.countDown();
        }).start();

        //5个线程消费
        for(int i = 0; i < 5; i++){
            new Thread(()->{
                try {
                    while (true){
                        TimeUnit.MILLISECONDS.sleep(5);
                        queue.take(); //空了会阻塞
                        y.getAndIncrement();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("添加元素个数:"+x);
        System.out.println("消费元素个数:"+y.get());
    }
}
